package app

import (
	"context"
	"fmt"
	"github.com/coreos/etcd/clientv3"
)

type LockMutex struct {
	Ttl     int64              //	租约时间
	Conf    clientv3.Config    //	etcd集群配置
	Key     string             //	etcd的key
	cancel  context.CancelFunc //	关闭续租的func
	lease   clientv3.Lease
	leaseID clientv3.LeaseID
	txn     clientv3.Txn
}

func (lm *LockMutex) init() error {
	var err error
	var ctx context.Context
	client, err := clientv3.New(lm.Conf)
	if err != nil {
		return err
	}
	lm.txn = clientv3.NewKV(client).Txn(context.TODO())
	lm.lease = clientv3.NewLease(client)
	leaseResp, err := lm.lease.Grant(context.TODO(), lm.Ttl)
	if err != nil {
		return err
	}
	ctx, lm.cancel = context.WithCancel(context.TODO())
	lm.leaseID = leaseResp.ID
	leaseRespChan, err := lm.lease.KeepAlive(ctx, lm.leaseID)
	go listenLeaseChan(leaseRespChan)
	return err
}

func listenLeaseChan(leaseRespChan <-chan *clientv3.LeaseKeepAliveResponse) {
	var (
		leaseKeepResp *clientv3.LeaseKeepAliveResponse
	)
	for {
		select {
		case leaseKeepResp = <-leaseRespChan:
			if leaseKeepResp == nil {
				fmt.Println("租约失效了")
				goto END
			}
		}
	}
END:
}

func (lm *LockMutex) Lock() error {
	err := lm.init()
	if err != nil {
		return err
	}
	//LOCK:
	lm.txn.If(clientv3.Compare(clientv3.CreateRevision(lm.Key), "=", 0)).
		Then(clientv3.OpPut(lm.Key, "", clientv3.WithLease(lm.leaseID))).
		Else()
	txnResp, err := lm.txn.Commit()
	if err != nil {
		return err
	}
	if !txnResp.Succeeded { //判断txn.if条件是否成立
		return fmt.Errorf("抢锁失败")
	}
	return nil
}

//释放锁
func (lm *LockMutex) UnLock() {
	lm.cancel()
	lm.lease.Revoke(context.TODO(), lm.leaseID)
	fmt.Println("释放了锁")
}
